﻿#region << 版 本 注 释 >>
/*----------------------------------------------------------------
 * 版权所有 (c) 2022 北京超维景生物科技有限公司 保留所有权利。
 * CLR版本：4.0.30319.42000
 * 文件名：Kernel
 * 
 * 创建者：huangyang
 * 电子邮箱：huangyang@tvscope.cn
 * 创建时间：2023/2/9 17:58:34
 * 版本：V1.0.0
 * 描述：
 *
 * ----------------------------------------------------------------
 * 修改人：
 * 时间：
 * 修改说明：
 *
 * 版本：V1.0.1
 *----------------------------------------------------------------*/
#endregion << 版 本 注 释 >>

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ImageK.Plugin.Frame;

namespace ImageK.Gui
{
    /// <summary>
    /// This class is an extended ImageWindow that displays stacks and hyperstacks.
    /// </summary>
    public class StackWindow : ImageWindow
    {
        protected TrackBar sliceSelector; // for backward compatibity with Image5D

        protected ScrollbarWithLabel cSelector, zSelector, tSelector;
        protected Thread thread;
        static readonly object _locker = new object();
        protected volatile bool done;
        protected volatile int slice;

        protected ScrollbarWithLabel animationSelector;

        bool hyperStack;
        int nChannels = 1, nSlices = 1, nFrames = 1;
        int c = 1, z = 1, t = 1;

        public StackWindow(ImagePlus imp) : this(imp, null)
        {
           
        }

        public StackWindow(ImagePlus imp, ImageCanvas ic):base(imp,ic)
        {
            addScrollbars(imp);
            this.MouseWheel += OnMouseWheel;
            //todo:

            thread = new Thread(Run);
            thread.Start();
        }

        protected override void OnFormClosing(FormClosingEventArgs e)
        {
            base.OnFormClosing(e);
            lock (_locker)
            {
                done = true;
                Monitor.Pulse(_locker);
            }

        }

        //线程处理zSelect
        private void Run()
        {
            while (!done)
            {
                try
                {
                    lock (_locker)
                    {
                        Monitor.Wait(_locker);
                    }
                }
                catch (Exception e) { }
                
                if (done) return;
                if (slice > 0)
                {
                    int s = slice;
                    slice = 0;
                    if (s != imp.getCurrentSlice())
                    {
                        imp.updatePosition(c, z, t);
                        setSlice(imp, s);
                    }
                }
            }
        }

        public override string createSubtitle()
        {
            string subtitle = base.createSubtitle();
            if (!hyperStack || imp.getStackSize() == 1)
                return subtitle;
            string s = "";
            int[] dim = imp.getDimensions(false);
            int channels = dim[2], slices = dim[3], frames = dim[4];
            if (channels > 1)
            {
                s += "c:" + imp.getChannel() + "/" + channels;
                if (slices > 1 || frames > 1) s += " ";
            }
            if (slices > 1)
            {
                s += "z:" + imp.getSlice() + "/" + slices;
                if (frames > 1) s += " ";
            }
            if (frames > 1)
                s += "t:" + imp.getFrame() + "/" + frames;
            // if (running2) 
            //     return s;
            return s;

            int index = subtitle.IndexOf(";");
            if (index != -1)
            {
                int index2 = subtitle.IndexOf("(");
                if (index2 >= 0 && index2 < index && subtitle.Length > index2 + 4 && !subtitle.Substring(index2 + 1, index2 + 4).Equals("ch:"))
                {
                    index = index2;
                    s = s + " ";
                }
                subtitle = subtitle.Substring(index, subtitle.Length);
            }
            else
                subtitle = "";
            return s + subtitle;
        }

        /// <summary>
        /// 鼠标滚轮事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <exception cref="NotImplementedException"></exception>
        private void OnMouseWheel(object? sender, MouseEventArgs e)
        {
            //todo:

            //e.Delta >0 滚轮向上，后退1帧，反之前进一帧
            int rotation = e.Delta > 0 ? -1 : 1;
            // bool ctrl = (e.getModifiers() & Event.CTRL_MASK) != 0;
            // if ((ctrl || IJ.shiftKeyDown()) && ic != null)
            // {
            //     Point loc = ic.getCursorLoc();
            //     int x = ic.screenX(loc.x);
            //     int y = ic.screenY(loc.y);
            //     if (rotation < 0)
            //         ic.zoomIn(x, y);
            //     else
            //         ic.zoomOut(x, y);
            //     return;
            // }
            if (hyperStack)
            {
                // if (rotation > 0)
                //     IJ.run(imp, "Next Slice [>]", "");
                // else if (rotation < 0)
                //     IJ.run(imp, "Previous Slice [<]", "");
            }
            else
            {
                int slice = imp.getCurrentSlice() + rotation;
                if (slice < 1)
                    slice = 1;
                else if (slice > imp.getStack().getSize())
                    slice = imp.getStack().getSize();
                setSlice(imp, slice);
                //todo:
                // imp.updateStatusbarValue();
                SyncWindows.setZ(this, slice);
            }
        }

        public void addScrollbars(ImagePlus imp)
        {
            //todo:
            ImageStack s = imp.getStack();
            int stackSize = s.getSize();
            int sliderHeight = 0;
            nSlices = stackSize;
            // hyperStack = imp.getOpenAsHyperStack();
            // //imp.setOpenAsHyperStack(false);
            int[] dim = imp.getDimensions();
            // int nDimensions = 2 + (dim[2] > 1 ? 1 : 0) + (dim[3] > 1 ? 1 : 0) + (dim[4] > 1 ? 1 : 0);
            // if (nDimensions <= 3 && dim[2] != nSlices)
            //     hyperStack = false;
            // if (hyperStack)
            // {
            //     nChannels = dim[2];
            //     nSlices = dim[3];
            //     nFrames = dim[4];
            // }
            // if (nSlices == stackSize) hyperStack = false;
            // if (nChannels * nSlices * nFrames != stackSize) hyperStack = false;
            // if (cSelector != null || zSelector != null || tSelector != null)
            //     removeScrollbars();
            ImageK ij = IJ.GetInstance();
            // //IJ.log("StackWindow: "+hyperStack+" "+nChannels+" "+nSlices+" "+nFrames+" "+imp);
            // if (nChannels > 1)
            // {
            //     cSelector = new ScrollbarWithLabel(this, 1, 1, 1, nChannels + 1, 'c');
            //     add(cSelector);
            //     sliderHeight += cSelector.getPreferredSize().height + ImageWindow.VGAP;
            //     if (ij != null) cSelector.addKeyListener(ij);
            //     cSelector.addAdjustmentListener(this);
            //     cSelector.setFocusable(false); // prevents scroll bar from blinking on Windows
            //     cSelector.setUnitIncrement(1);
            //     cSelector.setBlockIncrement(1);
            // }
            if (nSlices > 1)
            {
                char label = nChannels > 1 || nFrames > 1 ? 'z' : 't';
                if (stackSize == dim[2] && imp.isComposite()) label = 'c';
                zSelector = new ScrollbarWithLabel(this, 1, 1, 1, nSlices + 1, label);
                if (label == 't') animationSelector = zSelector;
                // zSelector.Location = new Point(5, ic.Height);
                add(zSelector);
                sliderHeight += 100;
                // sliderHeight += zSelector.getPreferredSize().height + ImageWindow.VGAP;
                // if (ij != null) zSelector.addKeyListener(ij);
                // zSelector.addAdjustmentListener(this);
                // zSelector.setFocusable(false);
                zSelector.ValueChanged += ZSelectorValueChanged;
                int blockIncrement = nSlices / 10;
                if (blockIncrement < 1) blockIncrement = 1;
                zSelector.setUnitIncrement(1);
                // zSelector.setBlockIncrement(blockIncrement);
                sliceSelector = zSelector.bar;
            }
            // if (nFrames > 1)
            // {
            //     animationSelector = tSelector = new ScrollbarWithLabel(this, 1, 1, 1, nFrames + 1, 't');
            //     add(tSelector);
            //     sliderHeight += tSelector.getPreferredSize().height + ImageWindow.VGAP;
            //     if (ij != null) tSelector.addKeyListener(ij);
            //     tSelector.addAdjustmentListener(this);
            //     tSelector.setFocusable(false);
            //     int blockIncrement = nFrames / 10;
            //     if (blockIncrement < 1) blockIncrement = 1;
            //     tSelector.setUnitIncrement(1);
            //     tSelector.setBlockIncrement(blockIncrement);
            // }
            // ImageWindow win = imp.getWindow();
            // if (win != null)
            //     win.setSliderHeight(sliderHeight);
        }


        private void ZSelectorValueChanged(object? sender, EventArgs e)
        {
            z = zSelector.getValue();
            int tmpSlice = hyperStack ? imp.getSlice() : imp.getCurrentSlice();
            if (z == tmpSlice ) 
                return;

            slice = (t - 1) * nChannels * nSlices + (z - 1) * nChannels + c;
            lock (_locker)
            {
                Monitor.Pulse(_locker);
            }
        }


        public void setAnimate(bool b)
        {
            if (running2 != b && animationSelector != null)
            {
                //todo:
                // animationSelector.updatePlayPauseIcon();
            }
                
            running2 = b;
        }

        public bool getAnimate()
        {
            return running2;
        }

        public int getNScrollbars()
        {
            int n = 0;
            if (cSelector != null) n++;
            if (zSelector != null) n++;
            if (tSelector != null) n++;
            return n;
        }

        public bool isHyperStack()
        {
            return hyperStack && getNScrollbars() > 0;
        }

        public void setPosition(int channel, int slice, int frame)
        {
            if (cSelector != null && channel != c)
            {
                c = channel;
                cSelector.setValue(channel);
                SyncWindows.setC(this, channel);
            }
            if (zSelector != null && slice != z)
            {
                z = slice;
                zSelector.setValue(slice);
                SyncWindows.setZ(this, slice);
            }
            if (tSelector != null && frame != t)
            {
                t = frame;
                tSelector.setValue(frame);
                SyncWindows.setT(this, frame);
            }
            this.slice = (t - 1) * nChannels * nSlices + (z - 1) * nChannels + c;
            imp.updatePosition(c, z, t);
            if (this.slice > 0)
            {
                int s = this.slice;
                this.slice = 0;
                if (s != imp.getCurrentSlice())
                    imp.setSlice(s);
            }
        }

        private void setSlice(ImagePlus imp, int n)
        {
            if (imp.isLocked())
            {
                IJ.beep();
                IJ.ShowStatus("Image is locked");
            }
            else
                imp.setSlice(n);
        }

        public bool validDimensions()
        {
            int c = imp.getNChannels();
            int z = imp.getNSlices();
            int t = imp.getNFrames();
            //IJ.log(c+" "+z+" "+t+" "+nChannels+" "+nSlices+" "+nFrames+" "+imp.getStackSize());
            int size = imp.getStackSize();
            if (c == size && c * z * t == size && nSlices == size && nChannels * nSlices * nFrames == size)
                return true;
            if (c != nChannels || z != nSlices || t != nFrames || c * z * t != size)
                return false;
            else
                return true;
        }

        /** Updates the stack scrollbar. */
        public void updateSliceSelector()
        {
            //todo:
            if (hyperStack || zSelector == null || imp == null)
                return;
            int stackSize = imp.getStackSize();
            int max = zSelector.getMaximum();
            if (max != (stackSize + 1))
                zSelector.setMaximum(stackSize + 1);


            if (imp != null && zSelector != null)
                zSelector.setValue(imp.getCurrentSlice());

            // EventQueue.invokeLater(new Runnable()
            // {
            //
            //     public void run()
            //     {
            //     if (imp != null && zSelector != null)
            //     zSelector.setValue(imp.getCurrentSlice());
            // }
            // });
        }

        public void removeScrollbars()
        {
            //todo:
            if (cSelector != null)
            {
                // remove(cSelector);
                // cSelector.removeAdjustmentListener(this);
                cSelector = null;
            }
            if (zSelector != null)
            {
                // remove(zSelector);
                // zSelector.removeAdjustmentListener(this);
                zSelector = null;
            }
            if (tSelector != null)
            {
                // remove(tSelector);
                // tSelector.removeAdjustmentListener(this);
                tSelector = null;
            }
        }
    }
}
